 /*******************************************************************************
  * Copyright (c) 2005, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal.cheatsheets.composite.model;

 import java.util.HashMap ;
 import java.util.Iterator ;
 import java.util.Map ;

 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.ui.IMemento;
 import org.eclipse.ui.XMLMemento;
 import org.eclipse.ui.cheatsheets.ICheatSheetManager;
 import org.eclipse.ui.internal.cheatsheets.CheatSheetPlugin;
 import org.eclipse.ui.internal.cheatsheets.composite.parser.ICompositeCheatsheetTags;
 import org.eclipse.ui.internal.cheatsheets.data.IParserTags;
 import org.eclipse.ui.internal.cheatsheets.state.ICheatSheetStateManager;
 import org.eclipse.ui.internal.cheatsheets.state.NoSaveStateManager;
 import org.eclipse.ui.internal.cheatsheets.views.CheatSheetManager;
 import org.eclipse.ui.internal.provisional.cheatsheets.ICompositeCheatSheetTask;
 import org.eclipse.ui.internal.provisional.cheatsheets.IEditableTask;
 import org.eclipse.ui.internal.provisional.cheatsheets.TaskEditor;

 /**
  * Class to save and restore composite cheatsheet state using a memento
  * There is a child memento for each task which contains keys for the
  * state complete. There is also a grandchild memento for
  * each task that has been started.
  */

 public class CompositeCheatSheetSaveHelper {
     private static final String DOT_XML = ".xml"; //$NON-NLS-1$
 private Map taskMementoMap;
     private ICheatSheetStateManager stateManager;

     /**
      * Constructor
      */
     public CompositeCheatSheetSaveHelper(ICheatSheetStateManager stateManager) {
         super();
         this.stateManager = stateManager;
     }

     public IStatus loadCompositeState(CompositeCheatSheetModel model, Map layoutData) {
         if (stateManager instanceof NoSaveStateManager) return Status.OK_STATUS;
         XMLMemento readMemento = CheatSheetPlugin.getPlugin().readMemento(model.getId() + DOT_XML);
         if (readMemento == null) {
             return Status.OK_STATUS;
         }
         taskMementoMap = createTaskMap(readMemento);
         loadTaskState(taskMementoMap, (AbstractTask)model.getRootTask());
         loadCheatsheetManagerData(readMemento, model.getCheatSheetManager());
         loadLayoutData(readMemento, layoutData);
         model.sendTaskChangeEvents();
         return Status.OK_STATUS;
     }

     private Map createTaskMap(XMLMemento readMemento) {
         Map map = new HashMap ();
         IMemento[] tasks = readMemento.getChildren(ICompositeCheatsheetTags.TASK);
         for (int i = 0; i < tasks.length; i++) {
             String taskId = tasks[i].getString(ICompositeCheatsheetTags.TASK_ID);
             if (taskId != null) {
                 map.put(taskId, tasks[i]);
             }
         }
         return map;
     }

     private void loadTaskState(Map taskMap, AbstractTask task) {
         ICompositeCheatSheetTask[] children = task.getSubtasks();
         IMemento memento = (IMemento)taskMap.get(task.getId());
         if (memento != null) {
             String state = memento.getString(ICompositeCheatsheetTags.STATE);
             if (state != null) {
                 task.setStateNoNotify(Integer.parseInt(state));
             }
         }
         if (task instanceof TaskGroup) {
             for (int i = 0; i < children.length; i++) {
                 loadTaskState(taskMap, (AbstractTask) children[i]);
             }
             ((TaskGroup)task).checkState();
         }
     }
     
     private void loadCheatsheetManagerData(XMLMemento readMemento, ICheatSheetManager manager) {
         if (manager == null) {
             return;
         }
         IMemento[] children = readMemento.getChildren(ICompositeCheatsheetTags.CHEAT_SHEET_MANAGER);
         for (int i = 0; i < children.length; i++) {
             IMemento childMemento = children[i];
             String key = childMemento.getString(ICompositeCheatsheetTags.KEY);
             String value = childMemento.getString(ICompositeCheatsheetTags.VALUE);
             manager.setData(key, value);
         }
     }
     
     private void loadLayoutData(XMLMemento readMemento, Map layoutData) {
         if (layoutData == null) {
             return;
         }
         IMemento[] children = readMemento.getChildren(ICompositeCheatsheetTags.LAYOUT_DATA);
         for (int i = 0; i < children.length; i++) {
             IMemento childMemento = children[i];
             String key = childMemento.getString(ICompositeCheatsheetTags.KEY);
             String value = childMemento.getString(ICompositeCheatsheetTags.VALUE);
             layoutData.put(key, value);
         }
     }

     /**
      * Save the state of a composite cheat sheet model
      * @param model
      * @param selectedTask
      * @param layoutData Will contain pairs of name/value Strings used to save and restore layout
      * @return
      */
     public IStatus saveCompositeState(CompositeCheatSheetModel model, Map layoutData) {
         if (stateManager instanceof NoSaveStateManager) return Status.OK_STATUS;
         XMLMemento writeMemento = XMLMemento.createWriteRoot(ICompositeCheatsheetTags.COMPOSITE_CHEATSHEET_STATE);
         writeMemento.putString(IParserTags.ID, model.getId());
         saveTaskState(writeMemento, (AbstractTask)model.getRootTask());
         saveCheatSheetManagerData(writeMemento, model.getCheatSheetManager());
         taskMementoMap = createTaskMap(writeMemento);
         if (layoutData != null) {
             saveMap(writeMemento, layoutData, ICompositeCheatsheetTags.LAYOUT_DATA);
         }
         return CheatSheetPlugin.getPlugin().saveMemento(writeMemento, model.getId() + DOT_XML);
     }

     private void saveCheatSheetManagerData(XMLMemento writeMemento, ICheatSheetManager manager) {
         if (!(manager instanceof CheatSheetManager)) {
             return;
         }
         Map data = ((CheatSheetManager)manager).getData();
         saveMap(writeMemento, data, ICompositeCheatsheetTags.CHEAT_SHEET_MANAGER);
     }

     private void saveMap(XMLMemento writeMemento, Map data, String tag) {
         for (Iterator iter = data.keySet().iterator(); iter.hasNext();) {
             String key = (String )iter.next();
             String value = (String ) data.get(key);
             IMemento childMemento = writeMemento.createChild(tag);
             childMemento.putString(ICompositeCheatsheetTags.KEY, key);
             childMemento.putString(ICompositeCheatsheetTags.VALUE, value);
         }
     }

     private void saveTaskState(IMemento writeMemento, AbstractTask task) {
         IMemento childMemento = writeMemento.createChild(ICompositeCheatsheetTags.TASK);
         childMemento.putString(ICompositeCheatsheetTags.TASK_ID, task.getId());
         childMemento.putString(ICompositeCheatsheetTags.STATE, Integer.toString(task.getState()));
         
         // If this is an editable task that has been started, completed or skipped save the editor state
 if (task instanceof IEditableTask && task.getState() != ICompositeCheatSheetTask.NOT_STARTED) {
             TaskEditor editor = getEditor(task);
             if (editor != null) {
                 IMemento taskDataMemento = childMemento.createChild(ICompositeCheatsheetTags.TASK_DATA);
                 editor.saveState(taskDataMemento);
             } else {
                 // The editor has not been started so save its previously loaded state
 IMemento taskData = getTaskMemento(task.getId());
                 if (taskData != null) {
                     IMemento previousDataMemento = childMemento.createChild(ICompositeCheatsheetTags.TASK_DATA);
                     previousDataMemento.putMemento(taskData);
                 }
             }
         }
         ICompositeCheatSheetTask[] subtasks = task.getSubtasks();
         for (int i = 0; i < subtasks.length; i++) {
             saveTaskState(writeMemento, (AbstractTask)subtasks[i]);
         }
     }

     private TaskEditor getEditor(AbstractTask task) {
         if (task instanceof EditableTask) {
             return ((EditableTask)task).getEditor();
         }
         return null;
     }

     public IMemento getTaskMemento(String id) {
         if (taskMementoMap == null) {
             return null;
         }
         IMemento childMemento = (IMemento)taskMementoMap.get(id);
         if (childMemento == null) {
             return null;
         }
         return childMemento.getChild(ICompositeCheatsheetTags.TASK_DATA);
     }

     public void clearTaskMementos() {
         taskMementoMap = null;
     }
     
     public void clearTaskMemento(String id) {
         if (taskMementoMap != null) {
             taskMementoMap.remove(id);
         }
     }

 }

